package com.mk.web.io.file.client;

import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.mk.web.io.file.threadpool.Task;
import com.mk.web.io.file.threadpool.UserRejectHandler;
import com.mk.web.io.file.threadpool.UserThreadFactory;

/**
 * 有三种方式：
 1、java common.io    内部实现是遍历的方式，小文件夹的效率还好，比如我测试60G的目录，就很慢很慢了。
 2、jdk 7 的watch service    //经测试基本不可用。在一个40g的很深的目录下去新建和删除文件5分钟都没结果。主要原因是需要对每一个Path进行注册监控。
 3、jnotify                   直接调用windows的api，效率很高，也很简单，推荐使用。
 *
 * 监控的方式主要分为两种：扫描式和事件驱动式
 */
public class WatchServiceTest {

    private static ThreadPoolExecutor init() {
        BlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<>();
        RejectedExecutionHandler rejectHandler = new UserRejectHandler();
        ThreadFactory threadFactory = new UserThreadFactory("第一机房");
        ThreadPoolExecutor poolExecutor =
                new ThreadPoolExecutor(2, 10,
                        30 * 1000, TimeUnit.MILLISECONDS, blockingQueue, threadFactory, rejectHandler);
        return poolExecutor;
    }

    private static ScheduledExecutorService initScheduledPool(){
        return Executors.newScheduledThreadPool(5);
    }


    public static void main(String[] a) {
        ThreadPoolExecutor poolExecutor = init();
        ScheduledExecutorService scheduledExecutorService = initScheduledPool();


        final Path oriPath = Paths.get("d:/download/");
        try {
            WatchService watchService = FileSystems.getDefault().newWatchService();
            WatchService watchService2 = FileSystems.getDefault().newWatchService();
            //给path路径加上文件观察服务
            WatchKey register = oriPath.register(watchService,
                    StandardWatchEventKinds.ENTRY_CREATE/*,
                    StandardWatchEventKinds.ENTRY_MODIFY,
                    StandardWatchEventKinds.ENTRY_DELETE*/
            );
            WatchKey register2 = oriPath.register(watchService2,
                    StandardWatchEventKinds.ENTRY_CREATE/*,
                    StandardWatchEventKinds.ENTRY_MODIFY,
                    StandardWatchEventKinds.ENTRY_DELETE*/
            );
            System.out.println(register == register2);
            // start an infinite loop
            while (true) {
                final WatchKey key = watchService.take();

                for (WatchEvent<?> watchEvent : key.pollEvents()) {

                    final WatchEvent.Kind<?> kind = watchEvent.kind();

                    if (kind == StandardWatchEventKinds.OVERFLOW) {
                        continue;
                    }
                    //创建事件
                    if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
                        // 文件上传完成后需要有一个上传完成的标记文件, 如xxx.txt.ok
                        poolExecutor.execute(new Task());
                    }
                    //修改事件
                    if (kind == StandardWatchEventKinds.ENTRY_MODIFY) {

                    }
                    //删除事件
                    if (kind == StandardWatchEventKinds.ENTRY_DELETE) {

                    }
                    // get the filename for the event
                    final WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent;
                    final Path changedPath = watchEventPath.context();
                    // print it out
                    System.out.println(kind + " -> " + changedPath);
                    // System.out.println(changedPath + " -> " + changedPath.getRoot());
                    // System.out.println("isAbsolute" + " -> " + changedPath.isAbsolute());
                    Path absolutePath = Paths.get(oriPath.toString(), changedPath.toString());
                    // System.out.println("Absolute" + " -> " + absolutePath);
                    // System.out.println("isDirectory:" + " -> " + Files.isDirectory(absolutePath));
                    // System.out.println("isRegularFile:" + " -> " + Files.isRegularFile(absolutePath));

                    // File file = absolutePath.toFile();
                    // System.out.println("isDirectory:" + " -> " + file.isDirectory());
                    // System.out.println("isFile:" + " -> " + file.isFile());

                    // 如果是目录, 对当前目录注册一个watchService,
                    // 同时注册一个启动一个scheduled task 一天后, 自动取消当前watch, register.cancel();
                    /*scheduledExecutorService.schedule(new Runnable() {
                        @Override
                        public void run() {
                            register.cancel();
                        }
                    }, 24 * 60, TimeUnit.SECONDS);*/
                    scheduledExecutorService.schedule(new Runnable() {
                        @Override
                        public void run() {
                            register.cancel();
                            try {
                                watchService.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }, 1, TimeUnit.SECONDS);

                }
                // reset the keyf
                boolean valid = key.reset();
                // exit loop if the key is not valid (if the directory was
                // deleted,for
                if (!valid) {
                    break;
                }
            }

        } catch (IOException | InterruptedException ex) {
            System.err.println(ex);
        }

    }


}
